<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>终端</title>
    <link href="/res/layui/css/layui.css" rel="stylesheet">
    <link href="/res/css/xterm.css" rel="stylesheet">
    <link href="/res/css/web-ssh.css" rel="stylesheet">
</head>
<body>
<div class="flex-row">
    <p>延迟：<b id="delay" style="color: #16b777">0 ms</b></p>
    <p style="margin-left: 25px">当前会话id: <b>${id}</b></p>
</div>
<div id="terminal"></div>

<script src="/res/js/jquery.min.js"></script>
<script src="/res/layui/layui.js"></script>
<script src="/res/js/xterm.js"></script>
<script src="/res/js/socket.d.js"></script>
<script type="module">
    var loadIndex = layer.load(0);
    // 模拟关闭
    setTimeout(function () {
        layer.close(loadIndex)
    }, 5000);
    var terminal, wsSession, isInitTerminal = false
    layui.use(function () {
        var element = layui.element;
        var size = getSize()
        terminal = new Terminal({
            cursorBlink: true,
            columns: size.columns,
            rows: size.rows
        });
        // 行间高度
        terminal.options.lineHeight = 1.3
        terminal.open(document.getElementById('terminal'));
        terminal.onData(command => {
            send('cmd', command);
        });

        // 初始化ws
        initWs(terminal)
    });

    async function initWs(terminal) {
        wsSession = await SocketD.createClient("sd:ws://" + window.location.hostname + ":${port}/ws/terminal/index?id=${id}&type=${type}")
            .listen(SocketD.newEventListener()
                .doOnOpen(s => { //会话打开时
                    console.log('open')
                    setTimeout(() => {
                        // 发起初始化
                        var size = getSize(terminal)
                        sendSession(s, 'init', JSON.stringify({
                            columns: size.columns,
                            rows: size.rows
                        }));
                        testPing()
                    }, 200)
                    if (isInitTerminal) {
                        console.log('web终端已经初始化')
                        return
                    }
                    isInitTerminal = true
                    // 全屏
                    // terminal .options.windowOptions.fullscreenWin = true
                    $(window).resize(function () {
                        resizeTerm(terminal);
                    });
                    // resize 初始化
                    // resizeTerm(term);
                }).doOnMessage((s, m) => { //收到任意消息时
                    var type = m.entity().meta('type');
                    if (type === 'print') {
                        terminal.write(m.entity().dataAsString());
                    } else if (type === 'initComplete') {
                        setTimeout(() => {
                            layer.close(loadIndex)
                            layer.msg('终端初始化完成');
                        }, 800)
                    } else if (type === 'pong') {
                        var time = m.entity().dataAsString();
                        var delay = new Date().getTime() - parseInt(time, 10)
                        if (delay < 24)
                            $('#delay').css('color', '#16b777')
                        else if (delay < 240)
                            $('#delay').css('color', '#ffb800')
                        else
                            $('#delay').css('color', '#ff5722')
                        $('#delay').html(delay + ' ms')
                    } else if (type === 'close') {
                        terminal.writeln('')
                        terminal.writeln('已经失去服务端连接...')
                        terminal.close()
                    }
                })
            )
            .open();
    }

    // 关闭页面时
    window.onbeforeunload = function () {
        // 取消ping任务
        clearInterval(sil)
    };

    var sil = setInterval(() => {
        testPing()
    }, 12000)


    const testPing = () => {
        if (wsSession && wsSession.isValid()) {
            sendSession(wsSession, 'ping', new Date().getTime())
        } else {
            $('#delay').css('color', '#ff5722')
            $('#delay').html('- ms')
        }
    }

    /**
     * 发送指令
     * @param action 动作
     * @param str 内容，必须是string
     */
    const send = (action, str) => {
        const entity = SocketD.newEntity(str);
        entity.metaPut('type', action)
        wsSession.send("/", entity);
    }

    /**
     * 发送指令
     * @param session 会话
     * @param action 动作
     * @param str 内容，必须是string
     */
    const sendSession = (session, action, str) => {
        const entity = SocketD.newEntity(str);
        entity.metaPut('type', action)
        session.send("/", entity);
    }

    function getSize(terminal) { // 及时调整宽度
        const columns = parseInt(window.innerWidth / 10, 10) - 1
        var rows = 10;
        var innerHeight = window.innerHeight - 200
        if (terminal)
            rows = parseInt(innerHeight / terminal.options.fontSize, 10) - 7
        else
            rows = parseInt(innerHeight / 15, 10) - 7
        return {columns, rows}
    }

    const resizeTerm = (terminal) => {
        const {columns, rows} = getSize(terminal)
        if (columns !== terminal.options.cols || rows !== terminal.options.rows) {
            terminal.resize(columns, rows);
            if (wsSession)
                send('resize', JSON.stringify({
                    columns,
                    rows,
                }));
        }
    };
</script>
</body>
</html>